class TileSet {
  final String name;
  final String imagePath;
  final int tileWidth;
  final int tileHeight;
  final int tileCount;
  final int columns;
  final int firstGid;

  TileSet({
    required this.name,
    required this.imagePath,
    required this.tileWidth,
    required this.tileHeight,
    required this.tileCount,
    required this.columns,
    required this.firstGid,
  });

  Map<String, dynamic> toMap() {
    return {
      'name': name,
      'imagePath': imagePath,
      'tileWidth': tileWidth,
      'tileHeight': tileHeight,
      'tileCount': tileCount,
      'columns': columns,
      'firstGid': firstGid,
    };
  }

  factory TileSet.fromMap(Map<String, dynamic> map) {
    return TileSet(
      name: map['name'] ?? '',
      imagePath: map['imagePath'] ?? '',
      tileWidth: map['tileWidth'] ?? 32,
      tileHeight: map['tileHeight'] ?? 32,
      tileCount: map['tileCount'] ?? 0,
      columns: map['columns'] ?? 0,
      firstGid: map['firstGid'] ?? 1,
    );
  }
}

class MapLayer {
  final String id;
  String name;
  final int width;
  final int height;
  List<List<int>> data;
  bool visible;
  double opacity;
  bool isObjectLayer;

  MapLayer({
    required this.id,
    required this.name,
    required this.width,
    required this.height,
    required this.data,
    this.visible = true,
    this.opacity = 1.0,
    this.isObjectLayer = false,
  });

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'name': name,
      'width': width,
      'height': height,
      'data': data,
      'visible': visible,
      'opacity': opacity,
      'isObjectLayer': isObjectLayer,
    };
  }

  factory MapLayer.fromMap(Map<String, dynamic> map) {
    return MapLayer(
      id: map['id'] ?? '',
      name: map['name'] ?? '',
      width: map['width'] ?? 0,
      height: map['height'] ?? 0,
      data: (map['data'] as List<dynamic>?)?.map((row) => 
        (row as List<dynamic>).cast<int>()).toList() ?? [],
      visible: map['visible'] ?? true,
      opacity: map['opacity'] ?? 1.0,
      isObjectLayer: map['isObjectLayer'] ?? false,
    );
  }

  MapLayer copyWith({
    String? id,
    String? name,
    int? width,
    int? height,
    List<List<int>>? data,
    bool? visible,
    double? opacity,
    bool? isObjectLayer,
  }) {
    return MapLayer(
      id: id ?? this.id,
      name: name ?? this.name,
      width: width ?? this.width,
      height: height ?? this.height,
      data: data ?? List.from(this.data.map((row) => List<int>.from(row.map((cell) => cell is int ? cell : int.tryParse(cell.toString()) ?? 0)))),
      visible: visible ?? this.visible,
      opacity: opacity ?? this.opacity,
      isObjectLayer: isObjectLayer ?? this.isObjectLayer,
    );
  }
}

class TileMap {
  final String version;
  final String orientation;
  final String renderOrder;
  int width;
  int height;
  int tileWidth;
  int tileHeight;
  List<TileSet> tileSets;
  List<MapLayer> layers;
  int nextObjectId;
  int nextLayerId;

  TileMap({
    this.version = '1.0',
    this.orientation = 'orthogonal',
    this.renderOrder = 'right-down',
    required this.width,
    required this.height,
    required this.tileWidth,
    required this.tileHeight,
    required this.tileSets,
    required this.layers,
    this.nextObjectId = 1,
    this.nextLayerId = 2,
  });

  Map<String, dynamic> toMap() {
    return {
      'version': version,
      'orientation': orientation,
      'renderOrder': renderOrder,
      'width': width,
      'height': height,
      'tileWidth': tileWidth,
      'tileHeight': tileHeight,
      'tileSets': tileSets.map((ts) => ts.toMap()).toList(),
      'layers': layers.map((layer) => layer.toMap()).toList(),
      'nextObjectId': nextObjectId,
      'nextLayerId': nextLayerId,
    };
  }

  factory TileMap.fromMap(Map<String, dynamic> map) {
    return TileMap(
      version: map['version'] ?? '1.0',
      orientation: map['orientation'] ?? 'orthogonal',
      renderOrder: map['renderOrder'] ?? 'right-down',
      width: map['width'] ?? 100,
      height: map['height'] ?? 100,
      tileWidth: map['tileWidth'] ?? 32,
      tileHeight: map['tileHeight'] ?? 32,
      tileSets: List<TileSet>.from(
        map['tileSets']?.map((ts) => TileSet.fromMap(ts)) ?? [],
      ),
      layers: List<MapLayer>.from(
        map['layers']?.map((layer) => MapLayer.fromMap(layer)) ?? [],
      ),
      nextObjectId: map['nextObjectId'] ?? 1,
      nextLayerId: map['nextLayerId'] ?? 2,
    );
  }

  factory TileMap.createNew({
    required int width,
    required int height,
    required int tileWidth,
    required int tileHeight,
  }) {
    final layer = MapLayer(
      id: '1',
      name: '图层1',
      width: width,
      height: height,
      data: List.generate(
        height,
        (y) => List.generate(width, (x) => 0),
      ),
    );

    return TileMap(
      width: width,
      height: height,
      tileWidth: tileWidth,
      tileHeight: tileHeight,
      tileSets: [],
      layers: [layer],
    );
  }
}

enum EditMode {
  view,
  edit,
  delete,
}

class EditorState {
  final TileMap? currentMap;
  final int selectedTileId;
  final int currentLayerIndex;
  final EditMode editMode;
  final bool showGrid;
  final bool showRuler;
  final double zoomLevel;
  final String? currentFilePath;
  final List<List<List<int>>> undoStack;
  final List<List<List<int>>> redoStack;

  EditorState({
    this.currentMap,
    this.selectedTileId = 0,
    this.currentLayerIndex = 0,
    this.editMode = EditMode.view,
    this.showGrid = true,
    this.showRuler = true,
    this.zoomLevel = 1.0,
    this.currentFilePath,
    this.undoStack = const [],
    this.redoStack = const [],
  });

  EditorState copyWith({
    TileMap? currentMap,
    int? selectedTileId,
    int? currentLayerIndex,
    EditMode? editMode,
    bool? showGrid,
    bool? showRuler,
    double? zoomLevel,
    String? currentFilePath,
    List<List<List<int>>>? undoStack,
    List<List<List<int>>>? redoStack,
  }) {
    return EditorState(
      currentMap: currentMap ?? this.currentMap,
      selectedTileId: selectedTileId ?? this.selectedTileId,
      currentLayerIndex: currentLayerIndex ?? this.currentLayerIndex,
      editMode: editMode ?? this.editMode,
      showGrid: showGrid ?? this.showGrid,
      showRuler: showRuler ?? this.showRuler,
      zoomLevel: zoomLevel ?? this.zoomLevel,
      currentFilePath: currentFilePath ?? this.currentFilePath,
      undoStack: undoStack ?? this.undoStack,
      redoStack: redoStack ?? this.redoStack,
    );
  }
}